/**
 * Created by wzl on 2017/4/15.
 */
import * as THREE from 'three';

export function createShader(gl,type,source){
    let shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);
    let success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
    if (success) {
        return shader;
    }

    console.log(gl.getShaderInfoLog(shader));
    gl.deleteShader(shader);
}
export function createProgram(gl, vertexShader, fragmentShader) {
    let program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);
    let success = gl.getProgramParameter(program, gl.LINK_STATUS);
    if (success) {
        return program;
    }

    console.log(gl.getProgramInfoLog(program));
    gl.deleteProgram(program);
}

export function geom2VecArr(geometry,extent,tileSize){
    let extgeom=[];
    geometry.forEach((item)=>{
        extgeom.push(new THREE.Vector3( item.x/extent*tileSize, -(item.y/extent*tileSize),0 ));
    })
    return extgeom;
}
export function geojson2VectArr(geojson){
    let extgeom=[];
    geojson.geometry.coordinates.forEach((item)=>{
        extgeom.push(new THREE.Vector3(item.x,item.y,0));
    })
    return extgeom;
}

export function isClockWise(coords){
    let sum=0;
    for (let i=0;i<coords.length-1;i++){
        sum+=(coords[i+1][0] - coords[i][0]) * (coords[i+1][1] + coords[i][1]);
    }
    // console.log('sum: ',sum);
    return sum>0;
}

let semimajorAxis=6378137.0;
let maximumLatitude=mercatorAngleToGeodeticLatitude(Math.PI);
let rectangleSouthwestInMeters = {x:-semimajorAxis*Math.PI, y:-semimajorAxis*Math.PI};
let rectangleNortheastInMeters = {x:semimajorAxis*Math.PI, y:semimajorAxis*Math.PI};

function mercatorAngleToGeodeticLatitude (mercatorAngle) {
    return Math.PI*0.5 - (2.0 * Math.atan(Math.exp(-mercatorAngle)));
}
function geodeticLatitudeToMercatorAngle (latitude) {
    // Clamp the latitude coordinate to the valid Mercator bounds.
    if (latitude > maximumLatitude) {
        latitude = maximumLatitude;
    } else if (latitude < -maximumLatitude) {
        latitude = -maximumLatitude;
    }
    let sinLatitude = Math.sin(latitude);
    return 0.5 * Math.log((1.0 + sinLatitude) / (1.0 - sinLatitude));
}

export function radian2degree(val){
    return val/Math.PI*180;
}

export function degree2radian(val){
    return val*Math.PI/180;
}

export function project(lon,lat,height){
    let x = lon * semimajorAxis;
    let y = geodeticLatitudeToMercatorAngle(lat) * semimajorAxis;
    let z = height;

    let result={};

    result.x = x;
    result.y = y;
    result.z = z;
    return result;
}

export function unproject(x,y,z) {
    let oneOverEarthSemimajorAxis = 1/semimajorAxis;
    let longitude = x * oneOverEarthSemimajorAxis;
    let latitude = mercatorAngleToGeodeticLatitude(y * oneOverEarthSemimajorAxis);
    let height = z;

    let result={};

    result.longitude = longitude;
    result.latitude = latitude;
    result.height = height;
    return result;
}

function getNumberOfXTilesAtLevel(level) {
    return 1 << level;
}
function getNumberOfYTilesAtLevel(level) {
    return 1 << level;
}
export function mercatorPositionToTileXY(webMercatorPosition,level) {
    let xTiles = getNumberOfXTilesAtLevel(level);
    let yTiles = getNumberOfYTilesAtLevel(level);

    let overallWidth = rectangleNortheastInMeters.x - rectangleSouthwestInMeters.x;
    let xTileWidth = overallWidth / xTiles;
    let overallHeight = rectangleNortheastInMeters.y - rectangleSouthwestInMeters.y;
    let yTileHeight = overallHeight / yTiles;

    let distanceFromWest = webMercatorPosition.x - rectangleSouthwestInMeters.x;
    let distanceFromNorth = rectangleNortheastInMeters.y - webMercatorPosition.y;

    let xTileCoordinate = distanceFromWest / xTileWidth | 0;
    if (xTileCoordinate >= xTiles) {
        xTileCoordinate = xTiles - 1;
    }
    let yTileCoordinate = distanceFromNorth / yTileHeight | 0;
    if (yTileCoordinate >= yTiles) {
        yTileCoordinate = yTiles - 1;
    }

    let result={};

    result.x = xTileCoordinate;
    result.y = yTileCoordinate;
    result.widthInMeters = xTileWidth;
    result.heightInMeters = yTileHeight;
    return result;
}
export function positionToTileXY(position, level) {
    let webMercatorPosition = project(position.lon*Math.PI/180,position.lat*Math.PI/180,position.height);
    return mercatorPositionToTileXY(webMercatorPosition,level);
}
export function getTileSize(level) {
    let xTiles = getNumberOfXTilesAtLevel(level);
    let yTiles = getNumberOfYTilesAtLevel(level);
    let overallWidth = rectangleNortheastInMeters.x - rectangleSouthwestInMeters.x;
    let xTileWidth = overallWidth / xTiles;
    let overallHeight = rectangleNortheastInMeters.y - rectangleSouthwestInMeters.y;
    let yTileHeight = overallHeight / yTiles;
    let result={};
    result.widthInMeters = xTileWidth;
    result.heightInMeters = yTileHeight;
    return result;
}
export function getTileExtentInMeters(x,y,level){
    let tileSize = getTileSize(level);
    let west = rectangleSouthwestInMeters.x+x*tileSize.widthInMeters;
    let south = rectangleNortheastInMeters.y-(y+1)*tileSize.heightInMeters;
    let east = rectangleSouthwestInMeters.x+(x+1)*tileSize.widthInMeters;
    let north = rectangleNortheastInMeters.y-y*tileSize.heightInMeters;
    return {
        west:west,
        south:south,
        east:east,
        north:north
    }
}
export function frustumIntersectTiles(frustum) {
    let southWest = new THREE.Vector3(rectangleSouthwestInMeters.x,rectangleSouthwestInMeters.y,0);
    let northEast = new THREE.Vector3(rectangleNortheastInMeters.x,rectangleNortheastInMeters.y,0);
    let box3 = new THREE.Box3(southWest,northEast,0);
    let arr = [];
    frustumIntersectTilesInLevel(frustum,0,box3,arr);
    // console.log(arr.length);
    // let tileXY = mercatorPositionToTileXY(arr[0].getCenter(),16)
    // console.log(tileXY.x,tileXY.y,16);
    return arr.map((el)=>{
        let tileXY = mercatorPositionToTileXY(el.getCenter(),16);
        // console.log(tileXY);
        return {x:tileXY.x,y:tileXY.y,level:16};
    });
}
function frustumIntersectTilesInLevel(frustum,level,box3,arr) {
    if(level===16) {
        arr.push(box3);
        return arr;
    }
    let southWestPoint = box3.min;
    let northEastPoint = box3.max;
    let center = new THREE.Vector3((southWestPoint.x+northEastPoint.x)/2,(southWestPoint.y+northEastPoint.y)/2,0);
    let nw = new THREE.Box3(new THREE.Vector3(southWestPoint.x,center.y,0),new THREE.Vector3(center.x,northEastPoint.y,0));
    let ne = new THREE.Box3(new THREE.Vector3(center.x,center.y,0),new THREE.Vector3(northEastPoint.x,northEastPoint.y,0));
    let sw = new THREE.Box3(new THREE.Vector3(southWestPoint.x,southWestPoint.y,0),new THREE.Vector3(center.x,center.y,0));
    let se = new THREE.Box3(new THREE.Vector3(center.x,southWestPoint.y,0),new THREE.Vector3(northEastPoint.x,center.y,0));
    if(frustum.intersectsBox(nw)){
        frustumIntersectTilesInLevel(frustum,level+1,nw,arr);
    }
    if(frustum.intersectsBox(ne)){
        frustumIntersectTilesInLevel(frustum,level+1,ne,arr);
    }
    if(frustum.intersectsBox(sw)){
        frustumIntersectTilesInLevel(frustum,level+1,sw,arr);
    }
    if(frustum.intersectsBox(se)){
        frustumIntersectTilesInLevel(frustum,level+1,se,arr);
    }
    //return arr;
}